﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework;

namespace Brain.Rendering
{
    public class LineDrawer
    {
        public BrainModel Cylinder { get; set; }

        internal List<Line3D> Lines;
        internal VertexPositionColor[] Vertices;
        internal BasicEffect BasicEffect;
        internal BasicEffect ThickLineEffect;

        public readonly int[] BoxIndices = new int[]
        {
            0, 1,
            1, 2,
            2, 3,
            3, 0,
            0, 4,
            1, 5,
            2, 6,
            3, 7,
            4, 5,
            5, 6,
            6, 7,
            7, 4,
        };
        private VertexPositionColor[] BoxVertices;

        public LineDrawer()
        {
            Cylinder = ModelUtil.GenerateCylinderMesh(1, 1, 32);

            Lines = new List<Line3D>();

            Vertices = new VertexPositionColor[2];
            Vertices[0] = new VertexPositionColor(Vector3.Zero, Color.White);
            Vertices[1] = new VertexPositionColor(Vector3.Forward, Color.White);

            this.BasicEffect = new BasicEffect(Engine.Instance.GraphicsDevice);
            this.ThickLineEffect = new BasicEffect(Engine.Instance.GraphicsDevice);

            BoxVertices = new VertexPositionColor[8];
        }

        public void Submit(Line3D obj)
        {
            Lines.Add(obj);
        }

        public void Remove(Line3D obj)
        {
            Lines.Remove(obj);
        }

        public void DrawBoundingBox(BoundingBox box, Matrix View, Matrix Projection, Vector3 Color)
        {
            // Editor mode, draw Bounding Boxes
            BasicEffect.View = View;
            BasicEffect.Projection = Projection;
            BasicEffect.World = Matrix.Identity;
            BasicEffect.DiffuseColor = Color;
            BasicEffect.VertexColorEnabled = true;

            Vector3[] boxVertices = box.GetCorners();
            for (int x = 0; x < boxVertices.Length; x++)
            {
                BoxVertices[x].Position = boxVertices[x];
                BoxVertices[x].Color = new Color(Color);
            }

            BasicEffect.CurrentTechnique.Passes[0].Apply();
            GraphicsDevice device = Engine.Instance.GraphicsDevice;
            device.DepthStencilState = DepthStencilState.Default;
#if !SILVERLIGHT
            device.DrawUserIndexedPrimitives<VertexPositionColor>(
                    PrimitiveType.LineList,
                    BoxVertices,
                    0,
                    8,
                    BoxIndices,
                    0,
                    BoxIndices.Length / 2);
#endif
        }

        public void DrawEverything(Matrix View, Matrix Projection)
        {
            GraphicsDevice device = Engine.Instance.GraphicsDevice;

            BasicEffect.View = View;
            BasicEffect.Projection = Projection;
            ThickLineEffect.View = View;
            ThickLineEffect.Projection = Projection;

            for (int i = 0; i < Lines.Count; i++)
            {
                Line3D line = Lines[i];

                if (line.Thickness == 0)
                {
                    BasicEffect.DiffuseColor = line.Color.ToVector3();
                    BasicEffect.VertexColorEnabled = true;

                    Vertices[0].Position = line.Start;
                    Vertices[0].Color = line.Color;

                    Vertices[1].Position = line.End;
                    Vertices[1].Color = line.Color;

                    BasicEffect.View = View;
                    BasicEffect.Projection = Projection;
                    BasicEffect.World = Matrix.Identity;
                    BasicEffect.CurrentTechnique.Passes[0].Apply();

                    device.DrawUserPrimitives<VertexPositionColor>(PrimitiveType.LineList,
                        this.Vertices, 0, 1);
                }
                else
                {
                    if (i == 5)
                    {
                    }

                    ThickLineEffect.DiffuseColor = line.Color.ToVector3();

                    ThickLineEffect.VertexColorEnabled = false;
                    ThickLineEffect.EnableDefaultLighting();
                    ThickLineEffect.PreferPerPixelLighting = true;

                    BrainModelMesh mesh = Cylinder.Meshes[0];

                    Vector3 dir = Vector3Util.Direction(line.Start, line.End);
                    Matrix m = Matrix.CreateFromAxisAngle(dir, MathHelper.ToRadians(90));

                    float length = Vector3.Distance(line.Start, line.End);

                    Matrix k = Matrix.CreateWorld(line.Start, dir, Vector3.Up);

                    /*ThickLineEffect.World = Matrix.CreateScale(line.Thickness, length, line.Thickness)
                        * Matrix.CreateRotationX(MathHelper.ToRadians(90)) * k *
                        Matrix.CreateTranslation(Vector3.Up * (length / 2f) + k.Forward * (length / 2f));*/
                    ThickLineEffect.World = Matrix.CreateScale(line.Thickness, length, line.Thickness)
                        * Matrix.CreateRotationX(MathHelper.ToRadians(90)) * k *
                        Matrix.CreateTranslation(Vector3.Up + (k.Forward * (length / 3f)));
                    ThickLineEffect.CurrentTechnique.Passes[0].Apply();

                    device.SetVertexBuffer(mesh.VertexBuffer);
                    device.Indices = mesh.IndexBuffer;

                    device.DrawIndexedPrimitives(PrimitiveType.TriangleList, 0, 0, mesh.NumVertices, 0, mesh.PrimitiveCount);
                }
            }
        }

        public void Reset()
        {
            if (!this.BasicEffect.IsDisposed)
            {
                this.BasicEffect.Dispose();
            }
            if (!this.ThickLineEffect.IsDisposed)
            {
                this.ThickLineEffect.Dispose();
            }
            Cylinder = ModelUtil.GenerateCylinderMesh(1, 1, 32);

            Lines.Clear();
            Lines.Capacity = 0;

            this.BasicEffect = new BasicEffect(Engine.Instance.GraphicsDevice);
            this.ThickLineEffect = new BasicEffect(Engine.Instance.GraphicsDevice);
        }
    }
}
